from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.utils.decorators import method_decorator
from drf_yasg.utils import swagger_auto_schema
from rest_framework import status, generics, viewsets
from rest_framework.authentication import BasicAuthentication, SessionAuthentication, TokenAuthentication
from rest_framework.authtoken.models import Token
from rest_framework.decorators import api_view, permission_classes, authentication_classes
from rest_framework.exceptions import APIException
from rest_framework.permissions import IsAuthenticated,IsAuthenticatedOrReadOnly
from rest_framework.response import Response
from rest_framework.views import APIView

from course.models import Course
from course.permissions import IsOwnerReadOnly
from course.serializers import CourseSerializer


# 当用户模型执行保存操作后执行
@receiver(post_save, sender=settings.AUTH_USER_MODEL)  # Django的信号机制
def generate_token(sender, instance=None, created=False, **kwargs):
    """
    创建用户时自动生成Token
    :param sender:
    :param instance:
    :param created:
    :param kwargs:
    :return:
    """
    if created:
        Token.objects.create(user=instance)


"""1 函数式编程 Function Based View"""


# authentication_classes 认证方式 优先于全局设置
# permission_classes 鉴权方式
@api_view(['GET', 'POST'])
@authentication_classes((BasicAuthentication, SessionAuthentication, TokenAuthentication))
@permission_classes((IsAuthenticated, IsOwnerReadOnly))
def course_list(request):
    """
    获取所有课程信息或新增一个课程
    :param request:
    :return:
    """
    if request.method == 'GET':
        # many 序列化多个对象all()
        s = CourseSerializer(instance=Course.objects.all(), many=True)
        return Response(data=s.data, status=status.HTTP_200_OK)

    elif request.method == 'POST':
        s = CourseSerializer(data=request.data, partial=True)  # partial 部分更新
        if s.is_valid():
            # s.save()
            # 保存额外字段 extra
            s.save(teacher=request.user)  # 设置用户为讲师
            return Response(data=s.data, status=status.HTTP_201_CREATED)
        return Response(s.errors, status=status.HTTP_400_BAD_REQUEST)


# authentication_classes 认证方式 优先于全局设置
# permission_classes 鉴权方式
@api_view(['GET', 'PUT', 'DELETE'])
@authentication_classes((BasicAuthentication, SessionAuthentication, TokenAuthentication))
@permission_classes((IsAuthenticated, IsOwnerReadOnly))
def course_detail(request, pk):
    """
    获取 更新 删除一个课程
    :param request:
    :param pk:
    :return:
    """
    try:
        course = Course.objects.get(pk=pk)
    except Course.DoesNotExist:
        return Response(data={"msg": "没有此课程信息"}, status=status.HTTP_404_NOT_FOUND)

    if request.method == 'GET':
        s = CourseSerializer(instance=course)
        return Response(data=s.data, status=status.HTTP_200_OK)

    if request.method == 'PUT':
        s = CourseSerializer(instance=course, data=request.data)
        if s.is_valid():
            s.save()
            return Response(data=s.data, status=status.HTTP_200_OK)
        return Response(data=s.errors, status=status.HTTP_400_BAD_REQUEST)
    if request.method == 'DELETE':
        course.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)


""" 2 类试图 Class Based View """


class CourseList(APIView):
    # authentication_classes 认证方式 优先于全局设置
    # authentication_classes = (BasicAuthentication, SessionAuthentication, TokenAuthentication)
    # permission_classes 鉴权方式
    permission_classes = (IsAuthenticated, IsOwnerReadOnly)
    # permission_classes = (IsAuthenticatedOrReadOnly,)
    def get(self, request):
        """

        :param request:
        :return:
        """
        instance = Course.objects.all()
        s = CourseSerializer(instance=instance, many=True)
        return Response(s.data, status=status.HTTP_200_OK)

    def post(self, request):
        """

        :param request:
        :return:
        """
        s = CourseSerializer(data=request.data)
        if s.is_valid():
            s.save(teacher=self.request.user)
            # print(type(request.data), type(s.data))
            # <class 'dict'> <class 'rest_framework.utils.serializer_helpers.ReturnDict'>
            return Response(data=s.data, status=status.HTTP_200_OK)
        return Response(data=s.errors, status=status.HTTP_400_BAD_REQUEST)


class CourseDetail(APIView):
    # authentication_classes 认证方式 优先于全局设置
    authentication_classes = (BasicAuthentication, SessionAuthentication, TokenAuthentication)
    # permission_classes 鉴权方式
    permission_classes = (IsAuthenticated, IsOwnerReadOnly)

    @staticmethod
    def get_object(pk):
        """

        :param pk:
        :return:
        """
        try:
            return Course.objects.get(pk=pk)
        except Course.DoesNotExist:
            # raise Exception()
            exception = APIException(detail={"msg": "没有此课程信息"})
            exception.status_code = status.HTTP_404_NOT_FOUND
            raise exception

    def get(self, request, pk):
        """
        :param request:
        :param pk:
        :return:
        """
        obj = self.get_object(pk)
        s = CourseSerializer(instance=obj)
        return Response(s.data, status=status.HTTP_200_OK)

    def put(self, request, pk):
        """
        :param request:
        :param pk:
        :return:
        """
        obj = self.get_object(pk)
        s = CourseSerializer(instance=obj, data=request.data)
        if s.is_valid():
            s.save()
            return Response(data=s.data, status=status.HTTP_200_OK)
        return Response(data=s.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk):
        """
        :param request:
        :param pk:
        :return:
        """
        obj = self.get_object(pk)
        obj.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)


""" 3 通用类视图 Generic Class Based View """


class GCourseList(generics.ListCreateAPIView):
    queryset = Course.objects.all()
    serializer_class = CourseSerializer

    # authentication_classes 认证方式 优先于全局设置
    authentication_classes = (BasicAuthentication, SessionAuthentication, TokenAuthentication)
    # permission_classes 鉴权方式
    permission_classes = (IsAuthenticated, IsOwnerReadOnly)

    def perform_create(self, serializer):
        serializer.save(teacher=self.request.user)


class GCourseDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Course.objects.all()
    serializer_class = CourseSerializer

    # authentication_classes 认证方式 优先于全局设置
    authentication_classes = (BasicAuthentication, SessionAuthentication, TokenAuthentication)
    # permission_classes 鉴权方式
    permission_classes = (IsAuthenticated, IsOwnerReadOnly)


""" 4 DRF的视图集viewsets """

# 自定义描述信息
@method_decorator(name="list", decorator=swagger_auto_schema(operation_summary="查询课程",operation_description="查询所有课程信息"))
@method_decorator(name="create", decorator=swagger_auto_schema(operation_summary="创建新课程",operation_description="创建一个新课程"))
class CourseViewSet(viewsets.ModelViewSet):
    queryset = Course.objects.all()
    serializer_class = CourseSerializer

    # authentication_classes 认证方式 优先于全局设置
    authentication_classes = (BasicAuthentication, SessionAuthentication, TokenAuthentication)
    # permission_classes 鉴权方式
    permission_classes = (IsAuthenticated, IsOwnerReadOnly)

    def perform_create(self, serializer):
        serializer.save(teacher=self.request.user)
